﻿using System;
using System.Collections.Generic;
using GeoAPI.Geometries;
using YJKGridTopologyCal.Geometries;
using YJKGridTopologyCal.Triangulate.QuadEdge;

namespace YJKGridTopologyCal.Triangulate
{
	public class VoronoiDiagramBuilder
	{
		public void SetSites(IGeometry geom)
		{
			this._siteCoords = DelaunayTriangulationBuilder.ExtractUniqueCoordinates(geom);
		}

		public void SetSites(ICollection<Coordinate> coords)
		{
			this._siteCoords = DelaunayTriangulationBuilder.Unique(CoordinateArrays.ToCoordinateArray(coords));
		}

		public Envelope ClipEnvelope
		{
			set
			{
				this._clipEnv = value;
			}
		}

		public double Tolerance
		{
			set
			{
				this._tolerance = value;
			}
		}

		private void Create()
		{
			if (this._subdiv != null)
			{
				return;
			}
			Envelope envelope = DelaunayTriangulationBuilder.Envelope(this._siteCoords);
			this._diagramEnv = envelope;
			double distance = Math.Max(this._diagramEnv.Width, this._diagramEnv.Height);
			this._diagramEnv.ExpandBy(distance);
			if (this._clipEnv != null)
			{
				this._diagramEnv.ExpandToInclude(this._clipEnv);
			}
			IList<Vertex> vertices = DelaunayTriangulationBuilder.ToVertices(this._siteCoords);
			this._subdiv = new QuadEdgeSubdivision(envelope, this._tolerance);
			new IncrementalDelaunayTriangulator(this._subdiv).InsertSites(vertices);
		}

		public QuadEdgeSubdivision GetSubdivision()
		{
			this.Create();
			return this._subdiv;
		}

		public IGeometryCollection GetDiagram(IGeometryFactory geomFact)
		{
			this.Create();
			return VoronoiDiagramBuilder.ClipGeometryCollection(this._subdiv.GetVoronoiDiagram(geomFact), this._diagramEnv);
		}

		private static IGeometryCollection ClipGeometryCollection(IGeometryCollection geom, Envelope clipEnv)
		{
			IGeometry geometry = geom.Factory.ToGeometry(clipEnv);
			List<IGeometry> list = new List<IGeometry>();
			for (int i = 0; i < geom.NumGeometries; i++)
			{
				IGeometry geometryN = geom.GetGeometryN(i);
				IGeometry geometry2 = null;
				if (clipEnv.Contains(geometryN.EnvelopeInternal))
				{
					geometry2 = geometryN;
				}
				else if (clipEnv.Intersects(geometryN.EnvelopeInternal))
				{
					geometry2 = geometry.Intersection(geometryN);
					geometry2.UserData = geometryN.UserData;
				}
				if (geometry2 != null && !geometry2.IsEmpty)
				{
					list.Add(geometry2);
				}
			}
			return geom.Factory.CreateGeometryCollection(GeometryFactory.ToGeometryArray(list));
		}

		private ICollection<Coordinate> _siteCoords;

		private double _tolerance;

		private QuadEdgeSubdivision _subdiv;

		private Envelope _clipEnv;

		private Envelope _diagramEnv;
	}
}
